﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Forms;

namespace Chromium_Updater
{
    public delegate void updateCheckCompleted(CheckResult r);
    public delegate void downloadProgressChanged(DownloadProgressChangedEventArgs e);
    public delegate void downloadFileCompleted(DownloadResult r);
    public delegate void installFinished(InstallResult r);

    class Updater
    {
        private string latest_revision = "0";
        private string pathToDownload = SettingsManager.download_dir + "\\mini_installer.exe";
        //
        private WebClient downloader;
        //
        public event updateCheckCompleted checkCompleted;
        public event downloadProgressChanged progressChanged;
        public event downloadFileCompleted fileDownloaded;
        public event installFinished finished;

        public Updater()
        {
            downloader = new WebClient();
            downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(downloader_DownloadStringCompleted);
            downloader.DownloadProgressChanged += new DownloadProgressChangedEventHandler(downloader_DownloadProgressChanged);
            downloader.DownloadFileCompleted += new AsyncCompletedEventHandler(downloader_DownloadFileCompleted);
        }

        #region Update Checking

        public DownloadStartResult checkForUpdateAsync()
        {
            if (downloader.IsBusy) { return DownloadStartResult.Busy; }
            try
            {
                downloader.DownloadStringAsync(new Uri(SettingsManager.latest_revision_url));
            }
            catch (ArgumentNullException)
            {
                return DownloadStartResult.InvalidURL;
            }
            catch (WebException)
            {
                if (isConnectedToInternet) { return DownloadStartResult.NetError; }
                else { return DownloadStartResult.NoInternet; }
            }
            return DownloadStartResult.Success;
        }

        private void downloader_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs d)
        {
            if (d.Error != null) { checkCompleted(CheckResult.Error); }
            try
            {
                latest_revision = d.Result;
                if (Convert.ToInt32(d.Result) > Convert.ToInt32(SettingsManager.current_revision))
                {
                    checkCompleted(CheckResult.UpdateAvailable);
                }
                else { checkCompleted(CheckResult.NoUpdateAvailable); }
            }
            catch
            {
                checkCompleted(CheckResult.Error);
            }
        }

        public string latestRevision
        {
            get { return latest_revision; }
        }

        #endregion

        #region Downloading

        public DownloadStartResult downloadUpdateAsync()
        {
            if (downloader.IsBusy) { return DownloadStartResult.Busy; }
            if (!Directory.Exists(SettingsManager.download_dir)) { Directory.CreateDirectory(SettingsManager.download_dir); }
            try
            {
                downloader.DownloadFileAsync(new Uri(SettingsManager.specific_revision_url + latest_revision + "/mini_installer.exe"), pathToDownload);
            }
            catch (WebException)
            {
                if (isConnectedToInternet) { return DownloadStartResult.NetError; }
                else { return DownloadStartResult.NoInternet; }
            }
            catch (ArgumentNullException)
            {
                return DownloadStartResult.InvalidURL;
            }
            return DownloadStartResult.Success;
        }

        private void downloader_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            progressChanged(e);
        }

        private void downloader_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null) { fileDownloaded(DownloadResult.Error); }
            fileDownloaded(DownloadResult.Success);
        }

        #endregion

        #region Installing

        public InstallStartResult installUpdate()
        {
            if (isChromiumRunning)
            {
                if (MessageBox.Show("Chromium Updater is trying to install revision: " + latest_revision + ", but Chromium or Chrome is running. Would you like Chromium Updater to update it and restart your browser?", "Chromium Updater", MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    return InstallStartResult.ChromiumRunning;
                }
                else
                {
                    if (!closeChromium())
                    {
                        return InstallStartResult.ChromiumRunning;
                    }
                }
            }
            new Thread(new ThreadStart(installerWatcher)).Start();
            return InstallStartResult.Success;
        }

        private void installerWatcher()
        {
            try
            {
                Process.Start(pathToDownload).WaitForExit(SettingsManager.installer_timeout * 1000);
            }
            catch (Exception)
            {
                finished(InstallResult.Error);
            }
            finished(InstallResult.Success);
        }

        #endregion

        #region Misc functions

        public bool isBusy
        {
            get { return downloader.IsBusy; }
        }

        private bool isConnectedToInternet
        {
            get
            {
                IPAddress[] addresslist = Dns.GetHostAddresses("www.google.com");
                if (addresslist[0].ToString().Length > 6) { return true; }
                else { return false; }
            }
        }

        private bool isChromiumRunning
        {
            get
            {
                if (Process.GetProcessesByName("chrome").Length > 0) { return true; }
                else { return false; }
            }
        }

        private bool closeChromium(bool safely = true)
        {
            Process[] chrome_procs = Process.GetProcessesByName("chrome");
            bool report = true;
            foreach (Process proc in chrome_procs)
            {
                if (!proc.CloseMainWindow())
                {
                    if (!safely)
                    {
                        proc.Kill();
                    }
                    else { report = false; }
                }
            }
            return report;
        }

        #endregion
    }

    #region Custom Returns

    public enum DownloadStartResult
    {
        Success,
        InvalidURL,
        NoInternet,
        NetError,
        Busy
    }

    public enum CheckResult
    {
        UpdateAvailable,
        NoUpdateAvailable,
        Error
    }

    public enum DownloadResult
    {
        Success,
        Error
    }

    public enum InstallStartResult
    {
        ChromiumRunning,
        Success
    }

    public enum InstallResult
    {
        Error,
        Success
    }

    #endregion
}
